﻿//-----------------------------------------------------------------------
// <Copyright>
// * Copyright (C) 2022 RuYiAdmin All Rights Reserved
// </Copyright>
//-----------------------------------------------------------------------

using Masuit.Tools.Hardware;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace RuYiAdmin.Net.Common.Utility
{
    /// <summary>
    /// 硬件监测工具
    /// </summary>
    public static class RuYiHardwareMonitorUtil
    {
        private const string MEMINFO_FILEPATH = "/proc/meminfo"; //内存信息文件
        private const string CPUSTAT_FILEPATH = "/proc/stat";    // 运行情况
        private const string CPUINFO_FILEPATH = "/proc/cpuinfo"; // CUP 信息文件
        static bool isrun = false;
        static Object HardwareMonitorInfo = new Object();
        /// <summary>
        /// 硬件监测
        /// </summary>
        /// <returns>硬件监测信息</returns>
        public static async Task<object> StartMonitoringAsync()
        {
            if (isrun)
            {
                return HardwareMonitorInfo;
            }
            try
            {
                isrun = true;
                HardwareMonitorInfo = new
                {
                    CpuCount = await GetCpuCount(),
                    CpuLoad = await GgetCpuLoad(),
                    CpuTemperature = await GetCPUTemperature(),
                    CpuInfo = await GetCpuInfo(),
                    LogicalDrives = await GetLogicalDrives(),
                    DiskInfo = await GetDiskInfo(),
                    LocalUsedIP = await GetLocalUsedIP(),
                    RamInfo = await GetRamInfo(),
                    OSArchitecture = Enum.GetName(typeof(Architecture), RuntimeInformation.OSArchitecture),
                    OSDescription = RuntimeInformation.OSDescription,
                    ProcessArchitecture = Enum.GetName(typeof(Architecture), RuntimeInformation.ProcessArchitecture),
                    FrameworkDescription = RuntimeInformation.FrameworkDescription,
                    Windows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows),
                    Is64BitOperatingSystem = Environment.Is64BitOperatingSystem,
                    Is64BitProcess = Environment.Is64BitProcess,
                    OSVersion = Environment.OSVersion,
                    CpuCore = Environment.ProcessorCount,
                    HostName = Environment.MachineName
                };
            }
            finally
            {
                isrun = false;
            }
            return HardwareMonitorInfo;
        }
        /// <summary>
        /// 获取逻辑驱动器的名称
        /// </summary>
        /// <returns></returns>
        private static async Task<string[]> GetLogicalDrives()
        {
            return await Task.Run(() =>
            {
                switch (Environment.OSVersion.Platform)
                {
                    case PlatformID.Win32S:
                    case PlatformID.Win32Windows:
                    case PlatformID.Win32NT:
                    case PlatformID.WinCE:
                        return Environment.GetLogicalDrives();
                    case PlatformID.Unix:
                    //TODO: Linux 逻辑驱动器的名称
                    case PlatformID.Xbox:
                        break;
                    case PlatformID.MacOSX:
                        break;
                    case PlatformID.Other:
                        break;
                    default:
                        break;
                }
                return null;
            });
        }

        /// <summary>
        /// 获取本机当前正在使用的IP地址
        /// </summary>
        /// <returns></returns>
        private static async Task<string> GetLocalUsedIP()
        {
            return await Task.Run(() =>
            {
                var ip = "";
                switch (Environment.OSVersion.Platform)
                {
                    case PlatformID.Win32S:
                    case PlatformID.Win32Windows:
                    case PlatformID.Win32NT:
                    case PlatformID.WinCE:
                        ip = SystemInfo.GetLocalUsedIP().ToString();
                        break;
                    case PlatformID.Unix:
                        ip = NetworkInterface.GetAllNetworkInterfaces()
                         .Where(c => c.NetworkInterfaceType
                         != NetworkInterfaceType.Loopback
                         && c.OperationalStatus == OperationalStatus.Up)
                         .SelectMany((NetworkInterface n) => n.GetIPProperties()
                         .UnicastAddresses.Select((UnicastIPAddressInformation u) => u.Address))
                         .FirstOrDefault().ToString();
                        break;
                    case PlatformID.Xbox:
                        break;
                    case PlatformID.MacOSX:
                        break;
                    case PlatformID.Other:
                        break;
                    default:
                        break;
                }
                return ip;
            });
        }
        /// <summary>
        /// 获取CPU温度
        /// </summary>
        /// <returns></returns>
        private static async Task<float> GetCPUTemperature()
        {
            return await Task.Run(() =>
            {
                switch (Environment.OSVersion.Platform)
                {
                    case PlatformID.Win32S:
                    case PlatformID.Win32Windows:
                    case PlatformID.Win32NT:
                    case PlatformID.WinCE:
                        return SystemInfo.GetCPUTemperature();
                    case PlatformID.Unix:
                    //TODO: Linux CPU温度待完善
                    case PlatformID.Xbox:
                        break;
                    case PlatformID.MacOSX:
                        break;
                    case PlatformID.Other:
                        break;
                    default:
                        break;
                }
                return 0;
            });
        }
        /// <summary>
        /// 获取磁盘每个分区可用空间
        /// </summary>
        /// <returns></returns>
        private static async Task<List<DiskInfo>> GetDiskInfo()
        {
            return await Task.Run(() =>
            {
                switch (Environment.OSVersion.Platform)
                {
                    case PlatformID.Win32S:
                    case PlatformID.Win32Windows:
                    case PlatformID.Win32NT:
                    case PlatformID.WinCE:
                        List<DiskInfo> diskInfo = SystemInfo.GetDiskInfo();
                        return diskInfo?.DistinctBy(t => t.SerialNumber).ToList();
                    case PlatformID.Unix:
                        //TODO: Linux 磁盘每个分区可用空间待完善
                    case PlatformID.Xbox:
                        break;
                    case PlatformID.MacOSX:
                        break;
                    case PlatformID.Other:
                        break;
                    default:
                        break;
                }
                return null;
            });
        }
        /// <summary>
        /// 获取CPU信息
        /// </summary>
        /// <returns></returns>
        private static async Task<List<CpuInfo>> GetCpuInfo()
        {
            return await Task.Run(async () =>
            {
                switch (Environment.OSVersion.Platform)
                {
                    case PlatformID.Win32S:
                    case PlatformID.Win32Windows:
                    case PlatformID.Win32NT:
                    case PlatformID.WinCE:
                        return SystemInfo.GetCpuInfo();
                    case PlatformID.Unix:
                        try
                        {
                            var cpuinfo = await ReadMultiLineStartingAsync(CPUINFO_FILEPATH, "model name");
                            var cpu = cpuinfo.Distinct().ToArray()[0].Split(':')[1];
                            List<CpuInfo> cpuInfos = new List<CpuInfo>();
                            cpuInfos.Add(new CpuInfo { Type = cpu });
                            return cpuInfos;
                        }
                        catch (Exception)
                        {

                        }
                        break;
                    case PlatformID.Xbox:
                        break;
                    case PlatformID.MacOSX:
                        break;
                    case PlatformID.Other:
                        break;
                    default:
                        break;
                }
                return null;
            });
        }

        /// <summary>
        /// 获取内存信息
        /// </summary>
        /// <returns></returns>
        private static async Task<RamInfo> GetRamInfo()
        {
            return await Task.Run(async () =>
            {
                switch (Environment.OSVersion.Platform)
                {
                    case PlatformID.Win32S:
                    case PlatformID.Win32Windows:
                    case PlatformID.Win32NT:
                    case PlatformID.WinCE:
                        return SystemInfo.GetRamInfo();
                    case PlatformID.Unix:
                        RamInfo ramInfo = new RamInfo();
                        var memTotalLine = await ReadLineStartingAsync(MEMINFO_FILEPATH, "MemTotal");
                        if (!string.IsNullOrWhiteSpace(memTotalLine)
                            && long.TryParse(new string(memTotalLine.Where(char.IsDigit).ToArray()), out var totalMemInKb))
                        {
                            ramInfo.PhysicalMemory = totalMemInKb * 1_000;
                        }
                        var memAvailableLine = await ReadLineStartingAsync(MEMINFO_FILEPATH, "MemAvailable");

                        if (!string.IsNullOrWhiteSpace(memAvailableLine))
                        {
                            memAvailableLine = await ReadLineStartingAsync(MEMINFO_FILEPATH, "MemFree");
                            if (!string.IsNullOrWhiteSpace(memAvailableLine)
                                && long.TryParse(new string(memAvailableLine.Where(char.IsDigit).ToArray()), out var availableMemInKb))
                            {
                                ramInfo.MemoryAvailable = availableMemInKb * 1_000;
                            }
                        }
                        return ramInfo;
                    case PlatformID.Xbox:
                        break;
                    case PlatformID.MacOSX:
                        break;
                    case PlatformID.Other:
                        break;
                    default:
                        break;
                }
                return null;
            });
        }
        /// <summary>
        /// 获取CPU的数量
        /// </summary>
        /// <returns></returns>
        private static async Task<int> GetCpuCount()
        {
            return await Task.Run(async () =>
            {
                switch (Environment.OSVersion.Platform)
                {
                    case PlatformID.Win32S:
                    case PlatformID.Win32Windows:
                    case PlatformID.Win32NT:
                    case PlatformID.WinCE:
                        return SystemInfo.GetCpuCount();
                    case PlatformID.Unix:
                        var cpuinfo = await ReadMultiLineStartingAsync(CPUINFO_FILEPATH, "physical id");
                        return cpuinfo.Distinct().Count();// CPU 数量
                    case PlatformID.Xbox:
                        break;
                    case PlatformID.MacOSX:
                        break;
                    case PlatformID.Other:
                        break;
                    default:
                        break;
                }
                return 0;
            });
        }
        /// <summary>
        /// 获取CPU占用率
        /// </summary>
        /// <returns></returns>
        private static async Task<float> GgetCpuLoad()
        {
            return await Task.Run(async () =>
            {
                switch (Environment.OSVersion.Platform)
                {
                    case PlatformID.Win32S:
                    case PlatformID.Win32Windows:
                    case PlatformID.Win32NT:
                    case PlatformID.WinCE:
                        return SystemInfo.CpuLoad;
                    case PlatformID.Unix:
                        var cpuLine1 = await ReadLineStartingAsync(CPUSTAT_FILEPATH, "cpu  ");
                        var cpuNumberStrings = cpuLine1.Split(' ').Skip(2);
                        if (cpuNumberStrings.Any(n => !long.TryParse(n, out _)))
                        {
                            return 0;
                        }
                        var cpuNumbers = cpuNumberStrings.Select(long.Parse).ToArray();
                        var user = cpuNumbers[0];
                        var nice = cpuNumbers[1];
                        var sys = cpuNumbers[2];
                        var idle = cpuNumbers[3];
                        var iowait = cpuNumbers[4];
                        var irq = cpuNumbers[5];
                        var softirq = cpuNumbers[6];
                        var all1 = user + nice + sys + idle + iowait + irq + softirq;
                        var idle1 = idle;
                        System.Threading.Thread.Sleep(100);
                        var cpu1Line2 = await ReadLineStartingAsync(CPUSTAT_FILEPATH, "cpu  ");
                        cpuNumberStrings = cpu1Line2.Split(' ').Skip(2);
                        if (cpuNumberStrings.Any(n => !long.TryParse(n, out _)))
                        {
                            return 0;
                        }
                        cpuNumbers = cpuNumberStrings.Select(long.Parse).ToArray();
                        user = cpuNumbers[0];
                        nice = cpuNumbers[1];
                        sys = cpuNumbers[2];
                        idle = cpuNumbers[3];
                        iowait = cpuNumbers[4];
                        irq = cpuNumbers[5];
                        softirq = cpuNumbers[6];
                        var all2 = user + nice + sys + idle + iowait + irq + softirq;
                        var idle2 = idle;
                        return (float)(all2 - all1 - (idle2 - idle1)) / (all2 - all1) * 100;
                    case PlatformID.Xbox:
                        break;
                    case PlatformID.MacOSX:
                        break;
                    case PlatformID.Other:
                        break;
                    default:
                        break;
                }
                return 0;
            });
        }
        /// <summary>
        /// 获取包含指定内容的一行
        /// </summary>
        /// <param name="path"></param>
        /// <param name="lineStartsWith"></param>
        /// <returns></returns>
        private static async Task<string> ReadLineStartingAsync(string path, string lineStartsWith)
        {
            using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 512, FileOptions.SequentialScan | FileOptions.Asynchronous))
            using (var r = new StreamReader(fs, Encoding.ASCII))
            {
                string line;
                while ((line = await r.ReadLineAsync()) != null)
                {
                    if (line.StartsWith(lineStartsWith, StringComparison.Ordinal))
                        return line;
                }
            }

            return null;
        }
        /// <summary>
        /// 获取包含指定内容的多行
        /// </summary>
        /// <param name="path"></param>
        /// <param name="lineStartsWith"></param>
        /// <returns></returns>
        private static async Task<string[]> ReadMultiLineStartingAsync(string path, string lineStartsWith)
        {
            using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 512, FileOptions.SequentialScan | FileOptions.Asynchronous))
            using (var r = new StreamReader(fs, Encoding.ASCII))
            {
                List<string> lines = new List<string>();
                string line;
                while ((line = await r.ReadLineAsync()) != null)
                {
                    if (line.StartsWith(lineStartsWith, StringComparison.Ordinal))
                        lines.Add(line);
                }
                return lines.ToArray();
            }
        }
    }
}
